﻿using OnlineFIR.Models;
using OnlineFIR.Utilities;

namespace OnlineFIR.Mechanic
{

    public class FIRAi1
    {
        private Map mymap;
        //private Map orimap;//仅用于测试时修改
        //成对的临时列表，表示一条轴上两个方向的共(最多)10个位置
        private List<byte> L;
        private List<byte> R;
        public FIRAi1(Map map)
        {
            //orimap = map;
            //不可以直接赋值，会造成引用传递
            mymap = map.Copy();
            L = new List<byte>(5);
            R = new List<byte>(5);
        }
        public void Test(int x,int y)
        {
            #region 测试getPossiblePoints()
            //List<Point> ps = GetPossiblePoints();
            //foreach(Point item in ps)
            //{
            //    orimap.Set(item, 3);
            //}
            #endregion

            #region 测试Extend()
            //orimap.ClearHighlight();
            //Extend(new Point(x, y), 0, 1);
            //foreach (Point item in L)
            //{
            //    orimap.Set(item, 3);
            //}
            //foreach (Point item in R)
            //{
            //    orimap.Set(item, 3);
            //}
            //Extend(new Point(x, y), 1, 1);
            //foreach (Point item in L)
            //{
            //    orimap.Set(item, 3);
            //}
            //foreach (Point item in R)
            //{
            //    orimap.Set(item, 3);
            //}
            //Extend(new Point(x, y), 2, 1);
            //foreach (Point item in L)
            //{
            //    orimap.Set(item, 3);
            //}
            //foreach (Point item in R)
            //{
            //    orimap.Set(item, 3);
            //}
            //Extend(new Point(x, y), 3, 1);
            //foreach (Point item in L)
            //{
            //    orimap.Set(item, 3);
            //}
            //foreach (Point item in R)
            //{
            //    orimap.Set(item, 3);
            //}
            #endregion

            #region 测试ConditionX()
            //Extend(new Point(x, y),0 , 1);
            //if(ConditionA(L,R) || ConditionA(R, L))
            //{
            //    orimap.Set(0, 0, 3);
            //}
            #endregion
        }
        private List<Point> GetPossiblePoints()
        {
            List<Point> res = new List<Point>();
            for(int i = 0; i < mymap.xsize; i++)
            {
                for(int j = 0; j < mymap.ysize; j++)
                {
                    if (!mymap.IsValid(i, j))
                    {
                        res.AddRange(GetAdjacentPoints(new Point(i, j)));
                    }
                }
            }
            return res;
        }
        private List<Point> GetAdjacentPoints(Point target)
        {
            int tx = target.x;
            int ty = target.y;
            List<Point> res = new List<Point>();
            if (mymap.IsValid(tx + 1, ty))
            {
                res.Add(new Point(tx + 1, ty));
            }
            if (mymap.IsValid(tx - 1, ty))
            {
                res.Add(new Point(tx - 1, ty));
            }
            if (mymap.IsValid(tx, ty + 1))
            {
                res.Add(new Point(tx, ty + 1));
            }
            if (mymap.IsValid(tx, ty - 1))
            {
                res.Add(new Point(tx, ty - 1));
            }

            if (mymap.IsValid(tx+1, ty+1))
            {
                res.Add(new Point(tx+1, ty+1));
            }
            if (mymap.IsValid(tx - 1, ty - 1))
            {
                res.Add(new Point(tx - 1, ty - 1));
            }
            if (mymap.IsValid(tx + 1, ty - 1))
            {
                res.Add(new Point(tx + 1, ty - 1));
            }
            if (mymap.IsValid(tx - 1, ty + 1))
            {
                res.Add(new Point(tx - 1, ty + 1));
            }
            return res;
        }

        public Point Decide()
        {
            List<Point> can = GetPossiblePoints();
            Point max = new Point();
            int maxScore=0;
            for(int i = 0; i < can.Count; i++)
            {
                Point p=can[i];
                int thisScore = GetTotalScore(p, 2);
                if (thisScore > maxScore)
                {
                    maxScore = thisScore;
                    max = p;
                }
            }
            return max;
        }
        private int GetTotalScore(Point p,byte me)
        {
            int res = 0;
            byte op;
            if (me == 1)
                op = 2;
            else
                op = 1;
            Extend(p, 0, me);
            res += GetPartialScore();
            Extend(p, 1, me);
            res += GetPartialScore();
            Extend(p, 2, me);
            res += GetPartialScore();
            Extend(p, 3, me);
            res += GetPartialScore();

            Extend(p, 0, op);
            res += GetPartialScore();
            Extend(p, 1, op);
            res += GetPartialScore();
            Extend(p, 2, op);
            res += GetPartialScore();
            Extend(p, 3, op);
            res += GetPartialScore();

            return res;
        }
        private int GetPartialScore()
        {
            int res = 0;
            //此时LR应该都已被设置好
            if (ConditionA(L, R) || ConditionA(R, L))
                res += 1000;
            if(ConditionB(L, R) || ConditionB(R, L))
                res += 100;
            if (ConditionC(L, R) || ConditionC(R, L))
                res += 10;
            if (ConditionD(L, R) || ConditionD(R, L))
                res += 1;
            return res;
        }
        private void Extend(Point p, int dir,byte me)
        {
            //dir=0表示上下，1表示右上左下，2表示右左，3表示右下左上
            L.Clear();
            R.Clear();
            if (dir == 0)
            {
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x - i, p.y);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        L.Add(mymap.GetOne(testing));
                    else
                        break;
                }
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x + i, p.y);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        R.Add(mymap.GetOne(testing));
                    else
                        break;
                }
            }
            else if(dir == 1)
            {
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x - i, p.y + i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        L.Add(mymap.GetOne(testing));
                    else
                        break;
                }
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x + i, p.y - i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        R.Add(mymap.GetOne(testing));
                    else
                        break;
                }
            }
            else if (dir == 2)
            {
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x, p.y + i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        L.Add(mymap.GetOne(testing));
                    else
                        break;
                }
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x, p.y - i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        R.Add(mymap.GetOne(testing));
                    else
                        break;
                }
            }
            else if (dir == 3)
            {
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x + i, p.y + i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        L.Add(mymap.GetOne(testing));
                    else
                        break;
                }
                for (int i = 1; i < 6; i++)
                {
                    Point testing = new Point(p.x - i, p.y - i);
                    if (mymap.IsInside(testing) && (mymap.GetOne(testing) != me))
                        R.Add(mymap.GetOne(testing));
                    else
                        break;
                }
            }
        }
        private bool ConditionA(List<byte> A, List<byte> B)
        {
            //如果对手下这里，这回合必死

            //MXXXX
            if(A.Count>=4 && A[0]!=0 && A[1]!=0 && A[2]!=0 && A[3] != 0)
            {
                return true;
            }
            //XMXXX
            if(A.Count>=3 && A[0]!=0 && A[1]!=0 && A[2]!=0)
            {
                if (B.Count >= 1 && B[0] != 0)
                    return true;
            }
            //XXMXX
            if(A.Count>=2 && A[0]!=0 && A[1] != 0)
            {
                if (B.Count >= 2 && B[0] != 0 && B[1] != 0)
                    return true;
            }
            return false;
        }
        private bool ConditionB(List<byte> A, List<byte> B)
        {
            //如果对手下这里，下回合必死

            //MXXXO
            if (A.Count >= 4 && A[0] != 0 && A[1] != 0 && A[2] != 0 && A[3] == 0)
                return true;
            //OXMXXO
            if(A.Count>=3 && A[0]!=0 && A[1]!=0 && A[2] == 0)
            {
                if (B.Count >= 2 && B[0] != 0 && B[1] == 0)
                    return true;
            }
            return false;
        }
        private bool ConditionC(List<byte> A, List<byte> B)
        {
            //如果对手下这里，下回合会产生致命威胁(conA/conB)

            //下回合满足ConditionA
            //WXXXOM
            //WXXXMO
            //XXOMX
            //XXMOX
            //XOXMX
            //下回合满足ConditionB
            //OXOMXO
            //OXXMO
            //OXMXO

            //WXXXOM
            if (A.Count == 4 && A[0] == 0 && A[1] != 0 && A[2] != 0 && A[3] != 0)
                return true;
            //WXXXMO
            if (A.Count == 3 && A[0] != 0 && A[1] != 0 && A[2] != 0)
            {
                if (B.Count >= 1 && B[0] == 0)
                    return true;
            }
            //XXOMX
            if (A.Count >= 3 && A[0] == 0 && A[1] != 0 && A[2] != 0) {
                if (B.Count >= 1 && B[0] != 0)
                    return true;
            }
            //XXMOX
            if (A.Count>=2 && A[0] != 0 && A[1] != 0)
            {
                if (B.Count >= 2 && B[0] == 0 && B[1] != 0)
                    return true;
            }
            //XOXMX
            if(A.Count>=3 && A[0]!=0 && A[1]==0 && A[2] != 0)
            {
                if (B.Count >= 1 && B[0] != 0)
                    return true;
            }

            //OXOMXO
            if (A.Count>=3 && A[0]==0 &&A[1]!=0 && A[2] == 0)
            {
                if (B.Count >= 2 && B[0] != 0 && B[1] == 0)
                    return true;
            }
            //OXXMO
            if(A.Count>=3 && A[0]!=0 && A[1]!=0 && A[2] == 0){
                if (B.Count >= 1 && B[0] == 0)
                    return true;
            }
            //OXMXO
            if(A.Count>=2 && A[0]!=0 && A[1] == 0)
            {
                if (B.Count >= 2 && B[0] != 0 && B[1] == 0)
                    return true;
            }
            return false;
        }
        private bool ConditionD(List<byte> A, List<byte> B)
        {
            //如果对手下这里，会产生ConditionC
            //WXXOOM
            if (A.Count == 4 && A[0] == 0 && A[1] == 0 && A[2] != 0 && A[3] != 0)
                return true;
            //WXXOMO
            if (A.Count == 3 && A[0] == 0 && A[1] != 0 && A[2] != 0)
            {
                if (B.Count >= 1 && B[0] == 0)
                    return true;
            }
            //WXXMOO
            if(A.Count == 2 && A[0]!=0 && A[1] != 0)
            {
                if (B.Count >= 2 && B[0] == 0 && B[1] == 0)
                    return true;
            }

            //XOMOX
            //XMOOX
            if(A.Count>=2 && A[0] == 0 && A[1] != 0)
            {
                if (B.Count >= 2 && B[0] == 0 && B[1] != 0)
                    return true;
            }
            if(A.Count >= 1 && A[0] != 0)
            {
                if (B.Count >= 3 && B[0] == 0 && B[1] == 0 && B[2] != 0)
                    return true;
            }

            //XMOOO
            //OXMOO
            //OOXMO
            //OOOXM
            if (A.Count + B.Count >= 4)
            {
                if (A.Count >= 1)
                {
                    if (A[0] != 0)
                        return true;
                }
            }
            return false;
        }
    }
}
